home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------------*\
- | TRLE.C - Convert DIBs into transparent RLEs
- \*--------------------------------------------------------------------------*/
-
- #include <windows.h>
- #include <windowsx.h>
- #include "dib.h"
-
- #ifdef WIN32
- #include <memory.h>
- #define _huge
- #define hmemcpy memcpy
- #endif
-
- //
- // you can control what type of pointers this code uses by defining
- // PRLE to be _huge, _far, or what ever.
- //
-
- //typedef BYTE *PRLE;
- //typedef BYTE FAR *PRLE;
- typedef BYTE _huge *PRLE;
-
- #define RLE_ESCAPE 0
- #define RLE_EOL 0
- #define RLE_EOF 1
- #define RLE_JMP 2
- #define RLE_RUN 3
-
- #define GEN_JMP(p,dx,dy) { \
- if (dx != 0 || dy != 0) \
- { \
- *(p)++ = RLE_ESCAPE; \
- *(p)++ = RLE_JMP; \
- *(p)++ = (BYTE)(dx); \
- *(p)++ = (BYTE)(dy); \
- }}
-
- #define GEN_EOL(p) { \
- *(p)++ = RLE_ESCAPE; \
- *(p)++ = RLE_EOL; }
-
- #define GEN_EOF(p) { \
- *(p)++ = RLE_ESCAPE; \
- *(p)++ = RLE_EOF; }
-
- #define GEN_ABS(p,cnt) { \
- *(p)++ = RLE_ESCAPE; \
- *(p)++ = (BYTE)(cnt); }
-
- #define GEN_RUN(p,cnt,b) { \
- *(p)++ = (BYTE)(cnt); \
- *(p)++ = (BYTE)(b); }
-
- #define GEN_JUMP(p,dx,dy) { int i; \
- for (i=0; i<(dx)/255; i++) \
- GEN_JMP(p,255,0); \
- \
- for (i=0; i<(dy)/255; i++) \
- GEN_JMP(p,0,255); \
- \
- GEN_JMP(p,(dx)%255,(dy)%255); }
-
- static void NEAR PASCAL DeltaFrame(LPBITMAPINFOHEADER, PRLE, PRLE, PRLE);
- static PRLE NEAR PASCAL EncodeFragment(PRLE pSource,PRLE pDest,int length);
-
- //
- // FindJump
- //
- // This routine returns the number of pixels in the 2 DIBs that can be
- // skipped over, because they are the same, or close enough within the
- // specified tolerance. It only checks one scan line.
- //
-
- static int _inline FindJumpLength(
- PRLE pb,
- int len,
- UINT uColor)
- {
- int i;
-
- for (i=0; i<len && pb[i]==(BYTE)uColor; i++)
- ;
-
- return i;
- }
-
- //
- // SkipAhead
- //
- // this routine returns the number of pixels that are not the same
- // in the two DIBs, there must be a run of at least gMinJumpSize pixels
- // in order to stop. (or end of line)
- //
-
- static int _inline FindFragmentLength(
- PRLE pb,
- int len,
- UINT uColor)
- {
- int i;
-
- for (i=0; i<len && pb[i]!=(BYTE)uColor; i++)
- ;
-
- return i;
- }
-
- /*
- ** Run-length encode wLength 8-bit pixels starting at pSource, storing
- ** the resulting data at pDest.
- */
- static PRLE NEAR PASCAL EncodeFragment(PRLE pSource,PRLE pDest,int length)
- {
- int i,j;
- BYTE b;
- PRLE p;
-
- while (length) {
- int nMaxLength;
-
- b = *pSource;
- p = pSource;
- nMaxLength = min(length, 255);
- for (i = 1; (i < nMaxLength) && (b == *(++p)); i++)
- ;
- if (length < RLE_RUN || i > 1) {
- GEN_RUN(pDest,i,b);
- pSource += i;
- length -= i;
- } else {
- for (j = RLE_RUN; (j < nMaxLength); j++) {
- b = *(pSource+j);
- p = pSource+j;
- /* stop if you run out of data or you find a run */
- for (i=1; i+j < length && i < RLE_RUN && (b == *(++p)); i++)
- ;
- if (i >= RLE_RUN)
- break;
- }
- GEN_ABS(pDest,j);
- length -= j;
- i = j;
- while (j--) {
- *pDest++ = *pSource++;
- }
- if (i & 1) /* Re-align after odd absolute run */
- *pDest++ = '\0'; // Set unused byte for DIFF checking.
- }
- }
-
- return pDest;
- }
-
- //
- // RleDib
- //
- // given a DIB make a RLE out of it, treating a passed color as transparent
- // the output buffer must be big enougth to hold the RLE, or bad things
- // will happen.
- //
- long RleDib(
- LPBITMAPINFOHEADER lpbi, // bitmap info
- LPVOID pDib, // DIB to compress
- UINT uColor, // trasnparent color (-1 for none)
- LPVOID pRle) // RLE bits output
- {
- PRLE pbDib = (PRLE)pDib;
- PRLE pbRle = (PRLE)pRle;
- PRLE pbDibT = pbDib;
- PRLE pbRleT = pbRle;
-
- int x,y;
- int dx,dy;
- int jx,jy; // delta jump values
-
- WORD wNextScan;
- WORD wWidthBytes;
-
- if (lpbi->biBitCount != 8 || lpbi->biCompression != 0)
- return 0;
-
- dx = (int)lpbi->biWidth;
- dy = (int)lpbi->biHeight;
-
- //
- // Calc next scan values, value to add to pointer when it is at the
- // end of the scan to get to the begining of the next.
- //
- wWidthBytes = (dx+3)&~3;
- wNextScan = wWidthBytes - dx;
-
- if (uColor == (UINT)-1) // just RLE it
- {
- for (y=0; y<dy; y++)
- {
- if (y > 0)
- GEN_EOL(pbRle);
-
- pbRle = EncodeFragment(pbDib,pbRle,dx);
- pbDib += wWidthBytes;
- }
-
- GEN_EOF(pbRle);
-
- lpbi->biSizeImage = (long)(pbRle-pbRleT);
- lpbi->biCompression = BI_RLE8;
- return (long)(pbRle-pbRleT);
- }
-
- //
- // start the delta framin'
- //
- x = 0;
- y = 0;
-
- while (y<dy)
- {
- #ifdef DEBUG
- if (pbDib != pbDibT + x + (DWORD)y*wWidthBytes)
- DebugBreak();
- if ((DWORD)pbRle & 1)
- DebugBreak();
- #endif
- jx = FindJumpLength(pbDib, dx-x, uColor);
-
- if (x+jx == dx) // we have a multi-line jump
- {
- pbDib += jx + wNextScan;
-
- for (jy=1; y+jy<dy && (jx=FindJumpLength(pbDib, dx, uColor))==dx; jy++)
- {
- pbDib += wWidthBytes;
- }
-
- if (jy+y >= dy)
- goto done;
-
- if (jx < x)
- {
- GEN_EOL(pbRle);
- jy--;
- y++;
- x=0;
- }
-
- GEN_JUMP(pbRle, jx-x, jy);
-
- x = 0;
- y += jy;
- }
- else if (jx > 0)
- {
- //
- // we have a "normal" jump
- //
- GEN_JUMP(pbRle,jx,0);
- }
- else if (jx = FindFragmentLength(pbDib, dx-x, uColor))
- {
- pbRle = EncodeFragment(pbDib, pbRle, jx);
- }
-
- x += jx;
- pbDib += jx;
- }
-
- //
- // all done.
- //
- done:
- GEN_EOF(pbRle);
-
- lpbi->biSizeImage = (long)(pbRle-pbRleT);
- lpbi->biCompression = BI_RLE8;
- return (long)(pbRle-pbRleT);
- }
-
- //
- // MakeRleDib
- //
- //
- LPBITMAPINFOHEADER MakeRleDib(
- LPBITMAPINFOHEADER lpbi, // packed DIB
- UINT uColor) // trasnparent color (-1 for upper corner)
- {
- LPBITMAPINFOHEADER p;
-
- p = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, DibSize(lpbi) * 2);
- hmemcpy(p, lpbi, lpbi->biSize + DibPaletteSize(lpbi));
-
- if (uColor == (UINT)-1)
- uColor = ((LPBYTE)DibXY(lpbi,0,0))[0];
-
- RleDib(p, DibPtr(lpbi), uColor, DibPtr(p));
-
- GlobalReAllocPtr(p, DibSize(p), 0);
-
- return p;
- }
-